<template>
  <!-- 支持同时上传图片和视频，或者只上传图片、只上传视频，可以预览、删除 -->
  <div class="any-upload-img-video">
    <el-upload
      :action="uploadApi()"
      list-type="picture-card"
      :data="acceptData"
      :limit="limit"
      :disabled="disabled"
      :multiple="multiple"
      :accept="accept"
      :file-list="fileList"
      :on-exceed="handleExceed"
      :on-change="(file, fileList) => handleChange(file, fileList)"
      :on-success="(response, file, fileList) => handleSuccess(response, file, fileList)"
      :before-upload="file => beforeUpload(file)"
    >
      <i slot="default" class="el-icon-camera"></i>
      <div slot="file" slot-scope="{ file }" class="custom-file-list">
        <!-- 删除 -->
        <i class="el-icon-close" v-if="!disabled" @click="handleRemove(file)"></i>

        <!-- 视频 -->
        <video
          class="el-upload-list__item-thumbnail"
          :src="file.url"
          alt=""
          @click="handlePreview(file, 'video')"
          v-if="
            ['mp4', 'ogg', 'webm', 'avi', 'wma', 'mpeg', 'mov', 'mlv'].indexOf(
             file.name.substring(file.name.indexOf('.') + 1)
          ) > -1"
        >
        </video>

        <!-- 图片 -->
        <img
          class="el-upload-list__item-thumbnail"
          :src="file.url"
          alt=""
          @click="handlePreview(file, 'img')"
          v-if="
            ['jpg', 'png', 'gif', 'jpeg', 'bmp', 'tif', 'avif', 'pcx', 'tga'].indexOf(
              file.name.substring(file.name.indexOf('.') + 1)
             ) > -1"
        />

        <el-progress
          type="circle"
          v-if="showProgress && file.url == uploadUrl"
          :percentage="Number(file.percentage)"
          :width="64"
        >
        </el-progress>
      </div>
    </el-upload>

    <!-- 图片预览 -->
    <van-image-preview
      v-model="isShowPreview"
      :images="previewImages"
      @change="onChange"
      :closeable="true"
      :startPosition="startPosition"
    >
      <template v-slot:index>第{{ imgIndex + 1 }}页</template>
    </van-image-preview>

    <!-- 视频预览 -->
    <div class="video-box" v-if="isShowVideoPreview">
      <van-icon name="cross" class="close" @click="isShowVideoPreview = !isShowVideoPreview"/>
      <video :src="videoUrl" controls alt=""></video>
    </div>

    <!-- 提示 -->
    <el-row class="limit-tip">
      <span>{{ tip }}</span>
    </el-row>
  </div>
</template>

<script>
const uidGenerator = () => {
  return '-' + parseInt(Math.random() * 10000 + 1, 10)
}

const getFileName = path => {
  if (path.lastIndexOf('\\') >= 0) {
    const reg = new RegExp('\\\\', 'g')
    path = path.replace(reg, '/')
  }
  return path.substring(path.lastIndexOf('/') + 1)
}

export default {
  name: 'EUploadImgVideo',
  props: {
    // 是否支持批量上传
    multiple: {
      type: Boolean,
      default: () => false
    },

    // 绑定的数据
    value: {
      type: [String, Array],
      required: false
    },

    // 禁用上传
    disabled: {
      type: Boolean,
      default: false,
      required: false
    },

    // 文件类型
    accept: {
      type: String,
      default: 'video/mp4,video/ogg,video/webm,image/png,image/jpg,image/gif,image/jpeg'
    },

    // 上传时附带的额外参数
    acceptData: {
      type: Object,
      default: () => {
        return {
          accept: '.mp4,.ogg,.webm,.png,.jpg,.gif,.jpeg', // 同时支持视频和图片时
          maxsize: 1024 * 1024 * 500,
          maxsize_text: '500M',
          videoTypeList: ['video/mp4', 'video/ogg', 'video/webm'],
          imageTypeList: ['image/png', 'image/jpg', 'image/jpeg', 'image/gif']
        }
      }
    },

    // 提示
    tip: {
      type: String,
      default: '最多上传10个文件，仅支持 mp4, ogg, webm, png, jpg, gif, jpeg 格式'
    },

    // 最大数量
    limit: {
      type: Number,
      default: 10
    },

    // 仅上传图片
    onlyImage: {
      type: Boolean,
      default: () => false
    },

    // 仅上传视频
    onlyVideo: {
      type: Boolean,
      default: () => false
    }
  },

  watch: {
    value: {
      handler(val, oldValue) {
        // 单选上传可以改变 fileList 的值，不用手动回显
        // 批量上传时不能改变 fileList 的值，页面会报错，如果有新增页面和编辑页面，需要手动调用 $refs.xxx.initFileList() 来回显图片或视频
        if (!this.multiple) {
          this.initFileList(val)
        }
      },
      // 立刻执行handler
      immediate: true
    }
  },

  data() {
    return {
      fileList: [], // 上传的文件数据
      isShowPreview: false, // 预览图片
      isShowVideoPreview: false, // 预览视频
      previewImages: [], // 预览的图片数据
      previewVideo: [], // 预览的视频数据
      imgIndex: 0, // 预览图片的索引
      videoUrl: '', // 预览视频的url
      startPosition: 0, // 预览图片的初始索引
      showProgress: false,
      uploadPercentage: 0
    }
  },

  methods: {
    // 图片/视频回显
    initFileList(array) {
      if (!array || array.length === 0) {
        this.fileList = []
        return
      }
      const fileList = []
      const arr = array || []
      for (let a = 0; a < arr.length; a++) {
        const url = this.getFileAccessHttpUrl(arr[a].url)
        fileList.push({
          name: getFileName(arr[a].name),
          url: url,
          uid: uidGenerator(),
          type: arr[a].type,
          response: {
            status: 'history',
            message: url
          }
        })
      }
      this.fileList = fileList
    },

    // url加/dispatch前缀，用于预览使用
    getFileAccessHttpUrl(url) {
      if (url.indexOf('/dispatch') > -1) {
        return url
      } else {
        return '/dispatch' + url
      }
    },

    // 上传文件地址
    uploadApi() {
      return '/dispatch/upload'
    },

    // 其他附件上传大小限制处理
    beforeUpload(file) {
      const { videoTypeList, imageTypeList } = this.acceptData
      let isVideo = true
      if (videoTypeList) {
        isVideo = videoTypeList.indexOf(file.type) !== -1
      }

      let isImg = true
      if (imageTypeList) {
        isImg = imageTypeList.indexOf(file.type) !== -1
      }

      // 只支持视频
      if (this.onlyVideo) {
        if (!isVideo) {
          this.$toast(`只能上传${this.acceptData.accept}的文件!`)
          return false
        }
      }

      // 只支持图片
      if (this.onlyImage) {
        if (!isImg) {
          this.$toast(`只能上传${this.acceptData.accept}格式的文件!`)
          return false
        }
      }

      // 默认：视频和图片都支持
      if (!isVideo && !isImg) {
        this.$toast(`只能上传${this.acceptData.accept}格式的文件!`)
        return false
      }

      // 文件大小限制
      const isLessThanMaxSize = file.size < this.acceptData.maxsize
      if (!isLessThanMaxSize) {
        this.$toast(`上传文件大小不能超过${this.acceptData.maxsize_text}!`)
        return false
      } else {
        this.$toast.loading({
          message: '请您耐心等待，文件上传中...',
          forbidClick: true,
          duration: 0,
          loadingType: 'spinner'
        })
      }
      return true
    },

    // 文件个数限制
    handleExceed() {
      this.$toast(`当前限制最多上传 ${this.limit} 个文件!`)
    },

    // 预览图片
    onChange(index) {
      this.imgIndex = index
    },

    handleChange(file, fileList, type) {
      this.uploadPercentage = 0
      if (file.status === 'ready') {
        this.showProgress = true
        this.uploadUrl = file.url
        const interval = setInterval(() => {
          if (this.uploadPercentage >= 95) {
            clearInterval(interval)
          }
          this.uploadPercentage += 1
        }, 20)
      }
      if (file.status === 'success') {
        this.uploadUrl = file.url
        this.uploadPercentage = 100
        this.showProgress = false
      }
    },

    // 上传图片成功
    handleSuccess(response, file, fileList) {
      this.$toast.clear()
      this.showProgress = false
      if (response.code === 200) {
        this.$toast('上传成功')
        const attachment = fileList.map(item => {
          if (item.response && item.response.data) {
            item.url = '/dispatch' + item.response.data || ''
          }
          return {
            name: item.name,
            url: item.url,
            uid: item.uid,
            type: item.raw ? item.raw.type : item.type
          }
        })
        this.fileList = attachment
        // 回显给业务，不携带 /dispatch 前缀
        this.$emit('change', this.fileList)
      } else {
        for (let i = 0; i < fileList.length; i++) {
          if (i + 1 === fileList.length) {
            fileList.splice(i, 1)
          }
        }
        this.$toast(response.msg)
      }
    },

    // 图片/视频预览
    handlePreview(file, type) {
      this.previewImages = []
      this.previewVideo = []
      if (type === 'img') {
        this.fileList.forEach((item, index) => {
          if (item.url === file.url) {
            this.startPosition = index
          }
        })
      }

      this.fileList.map(item => {
        // 预览图片的数据
        const { imageTypeList, videoTypeList } = this.acceptData
        let isImg = true
        if (imageTypeList) {
          isImg = imageTypeList.indexOf(item.type) !== -1
        }
        if (isImg) {
          this.previewImages.push(item.url)
        }

        // 预览视频的数据
        let isVideo = true
        if (videoTypeList) {
          isVideo = videoTypeList.indexOf(item.type) !== -1
        }
        if (isVideo) {
          this.previewVideo.push(item.url)
        }
      })

      if (type === 'img') {
        this.isShowPreview = true
      } else {
        this.videoUrl = file.url
        this.isShowVideoPreview = true
      }
    },

    // 删除
    handleRemove(file) {
      let index
      this.fileList.find((item, idx) => {
        if (item.uid === file.uid) {
          index = idx
          return
        }
      })
      if (typeof index !== 'undefined') {
        this.fileList.splice(index, 1)
      }
      // 回显给业务
      this.$emit('change', this.fileList)
    },

    // 长按保存图片
    touchStart(url, file) {
      clearTimeout(this.time)
      this.time = setTimeout(() => {
        // 这里就按照chrome等新版浏览器来处理
        const link = document.createElement('a')
        link.href = url
        link.setAttribute('download', file.name)
        link.click()
      }, 1000)
    },

    touchEnd() {
      clearTimeout(this.time)
    }
  }
}
</script>

<style lang="scss" scoped>
.custom-box-img {
  position: fixed;
  z-index: 1002;
  left: 0;
  right: 0;
  top: 1rem;
  display: flex;
  bottom: 0;
  background-color: #ffffff;
  align-items: center;

  .download-icon {
    margin: 0 auto;
    z-index: 1003;
    color: #ffffff;
    font-size: 18px;
    margin-top: 10px;

    ::v-deep .el-icon-download:before {
      font-size: 20px;
      color: #ffffff;
      vertical-align: middle;
    }

    .el-button--primary.is-disabled {
      background-color: #409eff;
      border-color: #409eff;
    }
  }

  .el-carousel__container {
    height: calc(100vh - 26px);
  }

  .el-carousel__arrow {
    background-color: rgba(31, 45, 61, 0.5);
    line-height: 36px;
  }

  .el-carousel__indicators--outside {
    bottom: 0;
    line-height: 26px;
  }
}

/deep/ .el-upload-list--picture-card .el-upload-list__item-thumbnail {
  width: 100%;
  height: 100%;
}

.limit-tip {
  color: #999999;
  display: inline-block;
  line-height: 20px;
  margin-top: 5px;
  font-size: 14px;
}

.video-box {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: #000;
  z-index: 9999;
  vertical-align: middle;
  text-align: center;

  video {
    height: 60%;
    margin-top: 20%;
    width: 100%;
  }

  .close {
    position: absolute;
    top: 10px;
    right: 10px;
    color: #fff;
    font-size: 28px;
  }
}

.custom-file-list {
  position: relative;
  height: 75px;
  font-size: 16px;

  .el-icon-close {
    position: absolute;
    right: 0;
    top: 0;
    z-index: 1000;
    display: block !important;
    font-size: 18px;
    color: #ffffff;
    background-color: #a9a6a6;
    border-radius: 100%;
  }
}

::v-deep .el-upload-list--picture-card .el-upload-list__item {
  width: 75px;
  height: 75px;
}

::v-deep .el-upload--picture-card {
  width: 75px;
  height: 73px;
  line-height: 78px;
  background-color: #f9f9f9;
}

::v-deep .el-upload-list--picture-card .el-progress {
  width: 75px !important;
}

::v-deep .el-progress-circle {
  width: 75px !important;
  height: 75px !important;
}

::v-deep .van-image-preview {
  top: 40px;
  height: 95%;
}
</style>
